/**
 * @file camera.c
 * @author Sevenfite (Sevenfite@163.com)
 * @brief 摄像头抽象层
 * @version 0.1
 * @date 2024-05-20
 *
 * @copyright Copyright (c) 2024
 *
 */

#include "camera.h"

#include "C_code_Log.h"
#include "stdbool.h"
#include "stdlib.h"
#include "string.h"
#include "usart.h"
#include "usart_port.h"

USART_Data usartCamera;
uint8_t USART_buf2[50];
CameraCmd_t cameraCmd = CAMERA_CMD_FIND_LINE;

typedef struct CameraData
{
    int lineRank;//寻线的偏差等级
    bool isFindNode;//是否找到节点
    int leftNumber;//数字识别左边的数字
    int rightNumber;//数字识别右边的数字
    int qrNumber;//二维码识别的数字
    bool error;//是否有线
    int distance;//加速距离
}CameraData;

static CameraData cameraData;


static bool camera_TransmitData(const char *data);
static int camera_getLineRank(char *data, int len);
static uint8_t camera_getIsFindNode(char *data, int len);
static bool camera_getMsg(char *data, int len);
static int camera_getLeftNumber(char *data, int len);
static int camera_getRightNumber(char *data, int len);
static int camera_getNumber(char *data, int len);
static bool camera_getError(char *data, int len);
static int camera_getqrcode(char *data, int len);
static int camera_getdistance(char *data, int len);

void camera_init(void) {
  USART_DataTypeInit(&usartCamera, &huart1, USART_buf2, sizeof(USART_buf2), DMA_MODE, NULL);
  char Cmd[2] = {0};
  Cmd[0] = CAMERA_CMD_FIND_LINE;
  camera_TransmitData(Cmd);
  LOG_INFO("camera init\n");
}
/**
 * @brief 从摄像头的缓冲区中获取线的偏差等级
 * 
 * @return int 
 */
int getLineRank() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  cameraData.lineRank =
      camera_getLineRank((char*)USART_GetData(&usartCamera), dataSize);
  return cameraData.lineRank;
}
/**
 * @brief 获取上一次的线的偏差等级
 * 
 * @return int 
 */
int getOldLineRank(){
  return cameraData.lineRank;
}
/**
 * @brief 从摄像头的缓冲区中获取是否找到节点
 * 
 * @return true 
 * @return false 
 */
bool getIsFindNode() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0
  cameraData.isFindNode=camera_getIsFindNode((char*)USART_GetData(&usartCamera), dataSize);
  return cameraData.isFindNode;
}
/**
 * @brief 从摄像头的缓冲区中获取数字识别左边的数字
 * 
 * @return uint8_t 
 */
uint8_t getLeftNumber() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  int data = camera_getLeftNumber((char*)USART_GetData(&usartCamera), dataSize);
  if (data >= 0)
    cameraData.leftNumber = data;
  return cameraData.leftNumber;
}
/**
 * @brief 从摄像头的缓冲区中获取数字识别右边的数字
 * 
 * @return uint8_t 
 */
uint8_t getRightNumber() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  int data = camera_getRightNumber((char*)USART_GetData(&usartCamera), dataSize);
  if (data >= 0)
    cameraData.rightNumber = data;  
  return cameraData.rightNumber;
}
/**
 * @brief 从摄像头的缓冲区中获取数字识别的数字
 * 
 * @return uint8_t 
 */
uint8_t getNumber() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  int data = camera_getNumber((char*)USART_GetData(&usartCamera), dataSize);
  if (data >= 0)
    cameraData.rightNumber = data;  
  return cameraData.rightNumber;
}
/**
 * @brief 从摄像头的缓冲区中获取是否识别到线
 * 
 * @return bool 
 */
bool getError() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  bool data = camera_getError((char*)USART_GetData(&usartCamera), dataSize);
  cameraData.error = data;  
  return cameraData.error;
}
/**
 * @brief 从摄像头的缓冲区中获取二维码中的数据
 * 
 * @return uint16_t 
 */
uint16_t getqrcode() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  int data = camera_getqrcode((char*)USART_GetData(&usartCamera), dataSize);
  if (data >= 0)
    cameraData.qrNumber = data;  
  return cameraData.qrNumber;
}
/**
 * @brief 从摄像头的缓冲区中获取加速距离
 * 
 * @return uint16_t 
 */
uint16_t getDistance() {
  int dataSize = 0;
  dataSize = USART_DataGetReceivedLen(&usartCamera);

  USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0

  int data = camera_getdistance((char*)USART_GetData(&usartCamera), dataSize);
  if (data > 0)
    cameraData.distance = data;
  else
    cameraData.distance = 1;
  return cameraData.distance;
}

int32_t getRoadBlockDistance(CameraCmd_t cmd)
{
  int32_t distance = getDistance();
  if(distance == 1 || distance == 0)
    return 1;
  if (cmd == CAMERA_CMD_GET_DISTANCE_ROADBLOCK)
  {
    distance -= AUTO_DISTANCE_MINUS_ROADBLOCK;
  }
  if (cmd == CAMERA_CMD_GET_DISTANCE_POINT)
  {
    distance -= AUTO_DISTANCE_MINUS_POINT;
  }
  if(distance <= 0)
    distance = 10;
  
  return distance;
}

/// @brief
/// @param cmd
/// @warning 要加上对发送是否成功的判断
void camera_SendCommand(CameraCmd_t cmd) {
  cameraCmd = cmd;
  char Cmd[2] = {0};
  Cmd[0] = cmd;
  camera_TransmitData(Cmd);
  LOG_INFO("camera send command: %d\n", cmd);
  while(1){
    if(USART_DataIsReceived(&usartCamera)){
      USART_DataResetReceivedFlag(&usartCamera);
      int dataSize = USART_DataGetReceivedLen(&usartCamera);
      USART_GetData(&usartCamera)[dataSize] = '\0';  // 把最后一位改成\0
      if(camera_getMsg((char*)USART_GetData(&usartCamera), dataSize)) break;
    }
  }
}
static bool camera_TransmitData(const char *data) {
  if (HAL_UART_Transmit(&huart1, (uint8_t *)data, strlen(data),
                        HAL_MAX_DELAY) == HAL_OK) { 
    return true;
  }
  LOG_ERROR("摄像头发送命令失败\n");
  return false;
}

/**
 * @brief 用于解析json数据中的数字
 * 
 * @param str 源数据
 * @param key 键值
 * @return int -1：没有找到key，其他：找到的数字
 * @warning 该函数只能解析数字，不能解析其他类型的数据
 * @warning 该函数不要用来解析-1，不能用于解析源json数据中存在value值与key值相同的情况
 */
int json_parsedInt(char* str,char* key){
  if(str==NULL || key==NULL) return -1;
  char* str1 = strstr(str,key);
  if (str1 == NULL) {
    LOG_ERROR("摄像头数据没有找到%s,数据为：%s\n", key,str);
    return -1;
  }
  str1 = strstr(str1, ":");
  if (str1 == NULL) {
    LOG_ERROR("摄像头数据没有找到%s后面的冒号,数据为：%s\n", key,str);
    return -1;
  }
  // 把指针指向数据后面的数字的第一个字符，去除空格和其他东西
  while (*str1 != '\0' && (*str1 < '0' || *str1 > '9')) {
    str1++;
  }
  char * end = str1;
  while (*end != '\0' && *end >= '0' && *end <= '9') {
    end++;
  }
  char temp = *end;
  *end = '\0';
  int result = atoi(str1);
  *end = temp;
  return result;
}

/**
 * @brief 处理摄像头数据，获取线的偏差等级
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int rank等级
 */
static int camera_getLineRank(char *data, int len) {
  int result;
  result = json_parsedInt(data,"line");
  if (result == -1) {//没有找到line
    result = 80;
  }else if(result==0)
  {
    LOG_ERROR("摄像头数据line后面的数字为0或转换失败,数据为：%s\n", data);
    result = 80;
  }
  return result;
}
/**
 * @brief 处理摄像头数据，获取是否找到节点
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return true 
 * @return false 
 */
static uint8_t camera_getIsFindNode(char *data, int len){
  int result;
  result = json_parsedInt(data,"node");
  if (result == -1) {//没有找到isFindNode
    result = 0;
  }
  return result;
}
/**
 * @brief 处理摄像头数据，获取msg的值
 * 
 * @param data 
 * @param len 
 * @return true 
 * @return false 
 */
static bool camera_getMsg(char *data, int len) {
  int result;
  result = json_parsedInt(data,"msg");
  if(result==-1) return false;
  return (bool)result;
}

/**
 * @brief 获取数字识别左边的数字
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int 左边的数字
 */
static int camera_getLeftNumber(char *data, int len) {
  int result;
  result = json_parsedInt(data,"left");
  return result;
}

/**
 * @brief 获取数字识别右边的数字
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int 右边的数字
 */
static int camera_getRightNumber(char *data, int len) {
  int result;
  result = json_parsedInt(data,"right");
  return result;
}
/**
 * @brief 获取数字识别的数字
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int 右边的数字
 */
static int camera_getNumber(char *data, int len) {
  int result;
  result = json_parsedInt(data,"number");
  return result;
}
/**
 * @brief 查看是否找到线
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int 0表示有线,1表示没找到线
 */
static bool camera_getError(char *data, int len) {
  int result;
  result = json_parsedInt(data,"Error");
  if(result == -1)
    return false;
  return (bool)result;
}
/**
 * @brief 获取二维码的信息
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int 二维码信息
 */
static int camera_getqrcode(char *data, int len) {
  int result;
  result = json_parsedInt(data,"qrcode");
  return result;
}
/**
 * @brief 获取距离信息
 * 
 * @param data 要处理的数据
 * @param len 数据的长度
 * @return int 距离信息
 */
static int camera_getdistance(char *data, int len) {
  int result;
  result = json_parsedInt(data,"distance");
  return result;
}

/*---------------------Test--------------------*/
#include "display.h"
#include "ABS_key.h"
#include "myconfig.h"
My_StatusTypeDef camera_Test(int key_Num) {
  static uint8_t cmd;
  char str[20];
  if (USART_DataIsReceived(&usartCamera)) {
    USART_DataResetReceivedFlag(&usartCamera);
    if(cameraCmd != CAMERA_CMD_NUMBER && cameraCmd != CAMERA_CMD_QR){
      sprintf(str, "lineRank:%d  ", getLineRank());
      displayStr(str, Display_firstCol, Display_firstRow, RED);
      if( cameraCmd==CAMERA_CMD_SHORT_FIND_NODE || cameraCmd==CAMERA_CMD_MIDDLE_FIND_NODE || 
          cameraCmd==CAMERA_CMD_REMOTE_FIND_NODE){
        sprintf(str, "isFindNode:%d    ", getIsFindNode());
        displayStr(str, Display_firstCol, Display_secondRow, RED);
      } else {
        displayStr("isFindNode:NULL", Display_firstCol, Display_secondRow, RED);
      }
    } else {
      if (cameraCmd == CAMERA_CMD_NUMBER)
        sprintf(str, "number:%d   ",getNumber());
      if (cameraCmd == CAMERA_CMD_QR)
        sprintf(str, "number:%d   ",getqrcode());
      displayStr(str, Display_firstCol, Display_firstRow, RED);
    }
    displayStr("normal", Display_firstCol + Display_OneChar, Display_thirdRow,RED);
    displayStr("bridge", Display_firstCol + Display_OneChar, Display_fourthRow,RED);
    displayStr("shortFindNode", Display_firstCol + Display_OneChar, Display_fifthRow,RED);
    displayStr("back", Display_firstCol + Display_OneChar,Display_fifthRow + Display_spaced,RED);
    displayStr("seesaw", Display_firstCol + Display_OneChar,Display_fifthRow + Display_spaced * 2,RED);
    displayStr("platform", Display_firstCol + Display_OneChar,Display_fifthRow + Display_spaced * 3,RED);
    displayStr("number", Display_firstCol + Display_OneChar,Display_fifthRow + Display_spaced * 4,RED);
    displayStr("middleFindNode", Display_firstCol + Display_OneChar, Display_fifthRow + Display_spaced * 5,RED);
    displayStr("remoteFindNode", Display_firstCol + Display_OneChar, Display_fifthRow + Display_spaced * 6,RED);
    displayStr("trace", Display_firstCol + Display_OneChar,Display_fifthRow + 7*Display_spaced,RED);
    displayStr("knife", Display_firstCol + Display_OneChar,Display_fifthRow + 8*Display_spaced,RED);
    displayStr("adjust", Display_firstCol + Display_OneChar,Display_fifthRow + 9*Display_spaced,RED);
    displayStr("qrcode", Display_firstCol + Display_OneChar,Display_fifthRow + 10*Display_spaced,RED);
    displayStr("distance", Display_firstCol + Display_OneChar,Display_fifthRow + 11*Display_spaced,RED);
    displayStr(">", Display_firstCol, Display_thirdRow + cmd * Display_spaced,RED);
  }
  if (key_Num == Key_ESC) {
    return MY_OK;
  } else if (key_Num == Key_OK) {
    switch (cmd)
    {
    case 0:
      camera_SendCommand(CAMERA_CMD_FIND_LINE);
      cameraCmd=CAMERA_CMD_FIND_LINE;
      break;
    case 1:
      camera_SendCommand(CAMERA_CMD_BRIDGE);
      cameraCmd=CAMERA_CMD_BRIDGE;
      break;
    case 2:
      camera_SendCommand(CAMERA_CMD_SHORT_FIND_NODE);
      cameraCmd=CAMERA_CMD_SHORT_FIND_NODE;
      break;
    case 3:
      camera_SendCommand(CAMERA_CMD_FIND_LINE_BACK);
      cameraCmd=CAMERA_CMD_FIND_LINE_BACK;
      break;
    case 4:
      camera_SendCommand(CAMERA_CMD_SEESAW);
      cameraCmd=CAMERA_CMD_SEESAW;
      break;
    case 5:
      camera_SendCommand(CAMERA_CMD_PLATFORM);
      cameraCmd=CAMERA_CMD_PLATFORM;
      break;
    case 6:
      camera_SendCommand(CAMERA_CMD_NUMBER);
      cameraCmd=CAMERA_CMD_NUMBER;
      break;
    case 7:
      camera_SendCommand(CAMERA_CMD_MIDDLE_FIND_NODE);
      cameraCmd=CAMERA_CMD_MIDDLE_FIND_NODE;
      break;
    case 8:
      camera_SendCommand(CAMERA_CMD_REMOTE_FIND_NODE);
      cameraCmd=CAMERA_CMD_REMOTE_FIND_NODE;
      break;
    case 9:
      camera_SendCommand(TRACE_R_CMD_FIND_LINE);
      cameraCmd=TRACE_R_CMD_FIND_LINE;
      break;
    case 10:
      camera_SendCommand(KNIFE_CMD_FIND_LINE);
      cameraCmd=KNIFE_CMD_FIND_LINE;
      break;
    case 11:
      camera_SendCommand(CAMERA_CMD_PLATFORM_ADJUST);
      cameraCmd=CAMERA_CMD_PLATFORM_ADJUST;
      break;
    case 12:
      camera_SendCommand(CAMERA_CMD_QR);
      cameraCmd=CAMERA_CMD_QR;
      break;
    case 13:
      camera_SendCommand(CAMERA_CMD_GET_DISTANCE_POINT);
      cameraCmd=CAMERA_CMD_GET_DISTANCE_POINT;
      break;
    default:
      break;
    }
  }
  else if(key_Num==Key_Down){
    displayStr(" ", Display_firstCol, Display_thirdRow + cmd * Display_spaced,RED);
    cmd++;
    cmd%=14;
  }
  else if(key_Num==Key_UP){
    displayStr(" ", Display_firstCol, Display_thirdRow + cmd * Display_spaced,RED);
    cmd--;
    cmd+=14;
    cmd%=14;
  }
  return MY_BUSY;
}